{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import time\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "%config InlineBackend.figure_format = 'retina'\n",
    "\n",
    "from sklearn import datasets\n",
    "from sklearn import linear_model\n",
    "from sklearn.svm import l1_min_c\n",
    "#from sklearn.linear_model import LinearRegression\n",
    "\n",
    "import h2o4gpu"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Linear Regression"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Linear Regression\n",
      "Predicted: [[ 39.93816196  41.93188356]]\n",
      "Coefficients: [[  1.9937216   10.03233797]]\n",
      "------------\n",
      "scikit-learn\n",
      "Predicted: [ 40.  42.]\n",
      "Coefficients: [ 2.]\n"
     ]
    }
   ],
   "source": [
    "# y = ax + b\n",
    "\n",
    "X = np.array([1,2,3,4,5,6,7,8,9,10])\n",
    "X = X.astype(float)\n",
    "\n",
    "y = 2*X + 10\n",
    "\n",
    "X = X[:, np.newaxis]\n",
    "X = np.hstack([X, np.ones((X.shape[0],1), dtype=X.dtype)])\n",
    "\n",
    "lm = h2o4gpu.LinearRegression()\n",
    "lm.fit(X, y)\n",
    "\n",
    "print('Linear Regression')\n",
    "print('Predicted:', lm.predict(np.array([[15.0, 1.0], [16.0, 1.0]])))\n",
    "print('Coefficients:', lm.X)\n",
    "\n",
    "# sklearn\n",
    "X = np.array([1,2,3,4,5,6,7,8,9,10])\n",
    "X = X[:, np.newaxis]\n",
    "# Values to predict\n",
    "X_test = np.array([15, 16])\n",
    "X_test = X_test[:, np.newaxis]\n",
    "\n",
    "sk_lm = linear_model.LinearRegression()\n",
    "sk_lm.fit(X, np.transpose(y))\n",
    "\n",
    "print('------------')\n",
    "print('scikit-learn')\n",
    "print('Predicted:', sk_lm.predict(X_test))\n",
    "print('Coefficients:', sk_lm.coef_)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Logistic Regression"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Data Prep"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2    50\n",
       "1    50\n",
       "0    50\n",
       "Name: 0, dtype: int64"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "iris = datasets.load_iris()\n",
    "\n",
    "X = iris.data\n",
    "y = iris.target\n",
    "\n",
    "dfX = pd.DataFrame(X)\n",
    "dfy = pd.DataFrame(y)\n",
    "\n",
    "dfy.loc[:,0].value_counts()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# making it a binary problem\n",
    "# removing third class\n",
    "X = X[y != 2]\n",
    "y = y[y != 2]\n",
    "\n",
    "# subtracting the mean\n",
    "X -= np.mean(X, 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "X_test = X[np.r_[40:50,90:100]]\n",
    "y_test = y[np.r_[40:50,90:100]]\n",
    "X = X[np.r_[:40,50:90]]\n",
    "y = y[np.r_[:40,50:90]]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### sklearn logistic regression"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "cs = l1_min_c(X, y, loss='log') * np.logspace(0, 3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.05513119697570801\n"
     ]
    }
   ],
   "source": [
    "start = time.time()\n",
    "clf = linear_model.LogisticRegression(C = 1.0, penalty = 'l1'\n",
    "                         #, tol=1e-6\n",
    "                        )\n",
    "coefs_ = []\n",
    "for c in cs:\n",
    "    clf.set_params(C=c)\n",
    "    clf.fit(X, y)\n",
    "    coefs_.append(clf.coef_.ravel().copy())\n",
    "print(time.time() - start)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n9C9eW/oaP33pp8xcNDOv3q9LP74/5Pvst+N+CXUmSZKUzzAvZS1ft5zbZ97O7+b9jkjM1XdssyPD\nBw73UpOSJKnJMcyr6G2s3Mjv3/w9t828jRXrV+TqLUpaMKzvMM7tdy7tW7ZPsENJkqSaGeZV1GYt\nnsVP/vkTXlv6Wl59aLehjBk8hp6deibTmCRJ0lZIXZgPIXwL+AJwANAf6AD8d4zxu4k2plRZunYp\nt864lcfeeiyv3q19N0YPHs2R3Y8khJBQd5IkSVsndWEe+AGZEL8a+ADok2w7SpOKygp+88ZvuHPm\nnawqX5Wrtyptxff2+x5n7ncmrVu0TrBDSZKkrZfGMD+cTIh/i8wZ+r8n247SYvon0/nJP3/CvE/n\n5dWP6n4UowaPYtcOuybUmSRJUt2kLszHGHPh3WkQ2hqL1yzmpuk38cT8J/Lqu3XcjdGDR3P4rocn\n1JkkSVL9pC7MF0IIYXotQ07ZaUbKK8v51dxfcdfLd7GmYk2u3qZFG87tdy6n7XMaLUtbJtihJElS\n/RRlmFfzN+OTGfzoxR/x1vK38urH9TyOkYNG0rVd14Q6kyRJKpyiDPMxxoE11bNn7A9s5HZUQEvX\nLuXm6Tfz+NuP59V7derF9w/6PgfvcnBCnUmSJBVeUYZ5NT8bKzfy6LxHuXXmraza8PlVatq0aMP5\n/c9nWN9hlJWWJdihJElS4RnmlXpzlszhRy/+iDlL5+TVv7Tblxg1eJRTaiRJUrNlmFdqrVi/gttn\n3s5v3/gtkZird+/Qne8P+b5XqZEkSc2eYV6pE2Pk8bcf5+bpN7Ns3bJcvWVJS87e/2zO2v8sWpW2\nSrBDSZKkxmGYV6q8+emb/PjFHzNj0Yy8+tBuQ7lqyFV079g9oc4kSZIaX+rCfAjhJOCk7I+bJkMf\nEkK4P/vfS2KMIxu9MTWotRVrmThrIg/OeZCKWJGrd23XldGDR3N0j6O9iZgkSSo6qQvzwAHA6dVq\nvbIPgHcBw3wz8vzC5/nxiz9m4eqFuVqL0ILT9j2N8/qdR9uytgl2J0mSlJzUhfkY47XAtQm3oUaw\neM1ixk0dx1MLnsqrH7jTgVx98NXsuf2eCXUmSZLUNKQuzKv5q4yVPDrvUSZMn8Cq8s+vGd+xZUdG\nDhrJ1/f8OiWhJMEOJUmSmgbDvJqUeZ/O4/p/XM+sxbPy6if2OpERg0bQuU3nhDqTJElqegzzahJq\n+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\nUur/A4QQmQSRZqBrAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f6fb597a5f8>"
      ]
     },
     "metadata": {
      "image/png": {
       "height": 277,
       "width": 377
      }
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(50, 4)\n"
     ]
    }
   ],
   "source": [
    "coefs_ = np.array(coefs_)\n",
    "plt.plot(np.log10(cs), coefs_)\n",
    "ymin, ymax = plt.ylim()\n",
    "plt.xlabel('log(C)')\n",
    "plt.ylabel('Coefficients')\n",
    "plt.title('Logistic Regression Path')\n",
    "plt.axis('tight')\n",
    "plt.show()\n",
    "print(coefs_.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_pred = clf.predict(X_test)\n",
    "y_pred"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[  9.99932222e-01,   6.77780147e-05],\n",
       "       [  9.99932222e-01,   6.77780147e-05],\n",
       "       [  9.99932222e-01,   6.77780147e-05],\n",
       "       [  9.99531863e-01,   4.68136891e-04],\n",
       "       [  9.96774248e-01,   3.22575200e-03],\n",
       "       [  9.99870913e-01,   1.29086709e-04],\n",
       "       [  9.99531863e-01,   4.68136891e-04],\n",
       "       [  9.99870913e-01,   1.29086709e-04],\n",
       "       [  9.99754161e-01,   2.45838631e-04],\n",
       "       [  9.99870913e-01,   1.29086709e-04],\n",
       "       [  3.12226255e-05,   9.99968777e-01],\n",
       "       [  8.60677825e-06,   9.99991393e-01],\n",
       "       [  4.10754010e-04,   9.99589246e-01],\n",
       "       [  3.60215791e-02,   9.63978421e-01],\n",
       "       [  1.13258920e-04,   9.99886741e-01],\n",
       "       [  1.13258920e-04,   9.99886741e-01],\n",
       "       [  1.13258920e-04,   9.99886741e-01],\n",
       "       [  5.94670599e-05,   9.99940533e-01],\n",
       "       [  2.05212724e-01,   7.94787276e-01],\n",
       "       [  2.15698555e-04,   9.99784301e-01]])"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "clf.predict_proba(X_test)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### H2O4GPU"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "classification = True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "logreg = h2o4gpu.LogisticRegression(alpha_max = 1.0\n",
    "                                    , alpha_min = 1.0\n",
    "                                   )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.9965429306030273\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<h2o4gpu.solvers.logistic.LogisticRegression at 0x7f6fb08b5940>"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "start = time.time()\n",
    "model = logreg.fit(X, y)\n",
    "print(time.time() - start)\n",
    "model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.5163793 ,  0.5907447 ,  0.58417682,  0.55988864,  0.50492926,\n",
       "         0.54436646,  0.47789073,  0.55462687,  0.45261082,  0.49840083,\n",
       "         0.53462668,  0.47810279,  0.50125192,  0.59493801,  0.54116415,\n",
       "         0.50917303,  0.52633727,  0.45435158,  0.602883  ,  0.52891951]])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_pred_h2o = model.predict(X_test)\n",
    "y_pred_h2o"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Xvsalpha\n",
      "[[-0.5599661  -0.01793422 -0.08567183  0.66957007]]\n",
      "[[-0.5599661  -0.01793422 -0.08567183  0.66957007]]\n",
      "np.shape(Xvsalpha)\n",
      "(1, 4)\n",
      "(1, 4)\n",
      "logloss_train\n",
      "[[ 0.68617965 -1.         -1.        ]]\n",
      "logloss_train\n",
      "[[ 0.68617965 -1.         -1.        ]]\n",
      "Best lambdas\n",
      "[[  1.48219694e-323]]\n",
      "[[  1.48219694e-323]]\n",
      "Best alphas\n",
      "[[ 1.]]\n",
      "[[ 1.]]\n",
      "Best tols\n",
      "[[ 0.01]]\n",
      "[[ 0.01]]\n"
     ]
    }
   ],
   "source": [
    "print(\"Xvsalpha\")\n",
    "print(logreg.x_vs_alphapure)\n",
    "print(model.x_vs_alphapure)\n",
    "\n",
    "print(\"np.shape(Xvsalpha)\")\n",
    "print(np.shape(logreg.x_vs_alphapure))\n",
    "print(np.shape(model.x_vs_alphapure))\n",
    "\n",
    "error_train = logreg.error_vs_alpha\n",
    "if classification:\n",
    "    print(\"logloss_train\")\n",
    "else:\n",
    "    print(\"rmse_train\")\n",
    "print(error_train)\n",
    "\n",
    "error_train = model.error_vs_alpha\n",
    "if classification:\n",
    "    print(\"logloss_train\")\n",
    "else:\n",
    "    print(\"rmse_train\")\n",
    "print(error_train)\n",
    "\n",
    "print(\"Best lambdas\")\n",
    "lambdas = logreg.lambdas_best\n",
    "print(lambdas)\n",
    "print(model.lambdas_best)\n",
    "\n",
    "print(\"Best alphas\")\n",
    "alphas = logreg.alphas_best\n",
    "print(alphas)\n",
    "print(model.alphas_best)\n",
    "\n",
    "print(\"Best tols\")\n",
    "tols = logreg.tols_best\n",
    "print(tols)\n",
    "print(model.tols_best)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-0.5599661 , -0.01793422, -0.08567183,  0.66957007]])"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "logreg.x_vs_alphapure"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'LogisticRegression' object has no attribute 'x_vs_alpha_lambdapure'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-17-13ae504034d8>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mmodel\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mX_full\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/h2o4gpu/solvers/elastic_net_base.py\u001b[0m in \u001b[0;36mX_full\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m   1125\u001b[0m     \u001b[0;34m@\u001b[0m\u001b[0mproperty\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1126\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0mX_full\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1127\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mx_vs_alpha_lambdapure\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   1128\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1129\u001b[0m     \u001b[0;34m@\u001b[0m\u001b[0mproperty\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mAttributeError\u001b[0m: 'LogisticRegression' object has no attribute 'x_vs_alpha_lambdapure'"
     ]
    }
   ],
   "source": [
    "model.X_full"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-0.5599661 , -0.01793422, -0.08567183,  0.66957007]])"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.X_best"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "136.42706084251404\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[[  3.06320700e-322]],\n",
       "\n",
       "       [[  2.22329541e-322]],\n",
       "\n",
       "       [[  1.58101007e-322]],\n",
       "\n",
       "       [[  1.13635099e-322]],\n",
       "\n",
       "       [[  8.39911598e-323]],\n",
       "\n",
       "       [[  5.92878775e-323]],\n",
       "\n",
       "       [[  4.44659081e-323]],\n",
       "\n",
       "       [[  2.96439388e-323]],\n",
       "\n",
       "       [[  1.97626258e-323]],\n",
       "\n",
       "       [[  1.48219694e-323]],\n",
       "\n",
       "       [[  9.88131292e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]],\n",
       "\n",
       "       [[  4.94065646e-324]]])"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "logreg = h2o4gpu.LogisticRegression(alpha_max = 1.0, \n",
    "                                    alpha_min = 1.0,\n",
    "                                    give_full_path = 1,\n",
    "                                    n_lambdas = 50,\n",
    "                                    glm_stop_early = False\n",
    "                                   )\n",
    "start = time.time()\n",
    "logreg.fit(X, y)\n",
    "print(time.time() - start)\n",
    "logreg.lambdas_full"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 136 seconds for 80 x 4  training_frame seems excessive"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.5163793 ,  0.5907447 ,  0.58417682,  0.55988864,  0.50492926,\n",
       "         0.54436646,  0.47789073,  0.55462687,  0.45261082,  0.49840083,\n",
       "         0.53462668,  0.47810279,  0.50125192,  0.59493801,  0.54116415,\n",
       "         0.50917303,  0.52633727,  0.45435158,  0.602883  ,  0.52891951]])"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y_pred_h2o"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Using GPU GLM solver with 2 GPUs\n",
      "no data\n",
      "no data\n",
      "no data\n",
      "Correct train inputs\n",
      "Detected np.float64 data\n",
      "Detected np.float64\n",
      "double precision fit\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<h2o4gpu.solvers.elastic_net_base.GLM at 0x7f6f78f87550>"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "logreg_path = h2o4gpu.GLM(family='logistic', verbose=100)\n",
    "logreg_path.fit(X, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "no data\n",
      "no data\n",
      "no data\n",
      "no data\n",
      "no data\n",
      "no data\n",
      "Correct prediction inputs\n",
      "Detected np.float64 data\n",
      "Detected np.float64\n",
      "double precision fit\n",
      "thecount=20 count_full_value=0 count_short_value=10 n=4 NUMALLOTHER=6 m_valid=20\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[ 0.5163793 ,  0.5907447 ,  0.58417682,  0.55988864,  0.50492926,\n",
       "         0.54436646,  0.47789073,  0.55462687,  0.45261082,  0.49840083,\n",
       "         0.53462668,  0.47810279,  0.50125192,  0.59493801,  0.54116415,\n",
       "         0.50917303,  0.52633727,  0.45435158,  0.602883  ,  0.52891951]])"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "logreg_path.predict(X_test)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### H2O3 Logistic Regression"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import h2o\n",
    "from h2o.estimators import H2OGeneralizedLinearEstimator "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Checking whether there is an H2O instance running at http://localhost:54321..... not found.\n",
      "Attempting to start a local H2O server...\n",
      "  Java Version: java version \"1.8.0_131\"; Java(TM) SE Runtime Environment (build 1.8.0_131-b11); Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)\n",
      "  Starting server from /home/karen/anaconda3/lib/python3.6/site-packages/h2o/backend/bin/h2o.jar\n",
      "  Ice root: /tmp/tmp6_q4vq_e\n",
      "  JVM stdout: /tmp/tmp6_q4vq_e/h2o_karen_started_from_python.out\n",
      "  JVM stderr: /tmp/tmp6_q4vq_e/h2o_karen_started_from_python.err\n",
      "  Server is running at http://127.0.0.1:54321\n",
      "Connecting to H2O server at http://127.0.0.1:54321... successful.\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div style=\"overflow:auto\"><table style=\"width:50%\"><tr><td>H2O cluster uptime:</td>\n",
       "<td>02 secs</td></tr>\n",
       "<tr><td>H2O cluster version:</td>\n",
       "<td>3.10.4.8</td></tr>\n",
       "<tr><td>H2O cluster version age:</td>\n",
       "<td>3 months and 8 days </td></tr>\n",
       "<tr><td>H2O cluster name:</td>\n",
       "<td>H2O_from_python_karen_yko529</td></tr>\n",
       "<tr><td>H2O cluster total nodes:</td>\n",
       "<td>1</td></tr>\n",
       "<tr><td>H2O cluster free memory:</td>\n",
       "<td>22.70 Gb</td></tr>\n",
       "<tr><td>H2O cluster total cores:</td>\n",
       "<td>40</td></tr>\n",
       "<tr><td>H2O cluster allowed cores:</td>\n",
       "<td>40</td></tr>\n",
       "<tr><td>H2O cluster status:</td>\n",
       "<td>accepting new members, healthy</td></tr>\n",
       "<tr><td>H2O connection url:</td>\n",
       "<td>http://127.0.0.1:54321</td></tr>\n",
       "<tr><td>H2O connection proxy:</td>\n",
       "<td>None</td></tr>\n",
       "<tr><td>H2O internal security:</td>\n",
       "<td>False</td></tr>\n",
       "<tr><td>Python version:</td>\n",
       "<td>3.6.1 final</td></tr></table></div>"
      ],
      "text/plain": [
       "--------------------------  ------------------------------\n",
       "H2O cluster uptime:         02 secs\n",
       "H2O cluster version:        3.10.4.8\n",
       "H2O cluster version age:    3 months and 8 days\n",
       "H2O cluster name:           H2O_from_python_karen_yko529\n",
       "H2O cluster total nodes:    1\n",
       "H2O cluster free memory:    22.70 Gb\n",
       "H2O cluster total cores:    40\n",
       "H2O cluster allowed cores:  40\n",
       "H2O cluster status:         accepting new members, healthy\n",
       "H2O connection url:         http://127.0.0.1:54321\n",
       "H2O connection proxy:\n",
       "H2O internal security:      False\n",
       "Python version:             3.6.1 final\n",
       "--------------------------  ------------------------------"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "h2o.init()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Parse progress: |█████████████████████████████████████████████████████████| 100%\n",
      "Parse progress: |█████████████████████████████████████████████████████████| 100%\n",
      "Parse progress: |█████████████████████████████████████████████████████████| 100%\n",
      "Parse progress: |█████████████████████████████████████████████████████████| 100%\n"
     ]
    }
   ],
   "source": [
    "hf_X = h2o.H2OFrame(X)\n",
    "hf_y = h2o.H2OFrame(y)\n",
    "hf_X_test = h2o.H2OFrame(X_test)\n",
    "hf_y_test = h2o.H2OFrame(y_test)\n",
    "hf_y = hf_y.asfactor()\n",
    "hf_y_test = hf_y_test.asfactor()\n",
    "hf = hf_X.cbind(hf_y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "glm Model Build progress: |███████████████████████████████████████████████| 100%\n",
      "0.44748449325561523\n"
     ]
    }
   ],
   "source": [
    "h2olr = H2OGeneralizedLinearEstimator(family = 'binomial')\n",
    "start = time.time()\n",
    "h2olr.train(x=['C1','C2', 'C3', 'C4'] ,y='C10', training_frame=hf)\n",
    "print(time.time()- start)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "glm prediction progress: |████████████████████████████████████████████████| 100%\n"
     ]
    }
   ],
   "source": [
    "hf_predict = h2olr.predict(hf_X_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<table>\n",
       "<thead>\n",
       "<tr><th style=\"text-align: right;\">  predict</th><th style=\"text-align: right;\">      p0</th><th style=\"text-align: right;\">         p1</th></tr>\n",
       "</thead>\n",
       "<tbody>\n",
       "<tr><td style=\"text-align: right;\">        0</td><td style=\"text-align: right;\">0.99894 </td><td style=\"text-align: right;\">0.00105951 </td></tr>\n",
       "<tr><td style=\"text-align: right;\">        0</td><td style=\"text-align: right;\">0.945188</td><td style=\"text-align: right;\">0.054812   </td></tr>\n",
       "<tr><td style=\"text-align: right;\">        0</td><td style=\"text-align: right;\">0.99902 </td><td style=\"text-align: right;\">0.000979667</td></tr>\n",
       "<tr><td style=\"text-align: right;\">        0</td><td style=\"text-align: right;\">0.993391</td><td style=\"text-align: right;\">0.00660907 </td></tr>\n",
       "<tr><td style=\"text-align: right;\">        0</td><td style=\"text-align: right;\">0.998349</td><td style=\"text-align: right;\">0.0016513  </td></tr>\n",
       "<tr><td style=\"text-align: right;\">        0</td><td style=\"text-align: right;\">0.993288</td><td style=\"text-align: right;\">0.00671188 </td></tr>\n",
       "<tr><td style=\"text-align: right;\">        0</td><td style=\"text-align: right;\">0.999591</td><td style=\"text-align: right;\">0.000408773</td></tr>\n",
       "<tr><td style=\"text-align: right;\">        0</td><td style=\"text-align: right;\">0.998476</td><td style=\"text-align: right;\">0.00152446 </td></tr>\n",
       "<tr><td style=\"text-align: right;\">        0</td><td style=\"text-align: right;\">0.999336</td><td style=\"text-align: right;\">0.000664274</td></tr>\n",
       "<tr><td style=\"text-align: right;\">        0</td><td style=\"text-align: right;\">0.99823 </td><td style=\"text-align: right;\">0.00176956 </td></tr>\n",
       "</tbody>\n",
       "</table>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": []
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hf_predict.head(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<table>\n",
       "<thead>\n",
       "<tr><th style=\"text-align: right;\">  predict</th><th style=\"text-align: right;\">         p0</th><th style=\"text-align: right;\">      p1</th></tr>\n",
       "</thead>\n",
       "<tbody>\n",
       "<tr><td style=\"text-align: right;\">        1</td><td style=\"text-align: right;\">0.00129041 </td><td style=\"text-align: right;\">0.99871 </td></tr>\n",
       "<tr><td style=\"text-align: right;\">        1</td><td style=\"text-align: right;\">0.000803543</td><td style=\"text-align: right;\">0.999196</td></tr>\n",
       "<tr><td style=\"text-align: right;\">        1</td><td style=\"text-align: right;\">0.00172183 </td><td style=\"text-align: right;\">0.998278</td></tr>\n",
       "<tr><td style=\"text-align: right;\">        1</td><td style=\"text-align: right;\">0.0125786  </td><td style=\"text-align: right;\">0.987421</td></tr>\n",
       "<tr><td style=\"text-align: right;\">        1</td><td style=\"text-align: right;\">0.00151788 </td><td style=\"text-align: right;\">0.998482</td></tr>\n",
       "<tr><td style=\"text-align: right;\">        1</td><td style=\"text-align: right;\">0.00658678 </td><td style=\"text-align: right;\">0.993413</td></tr>\n",
       "<tr><td style=\"text-align: right;\">        1</td><td style=\"text-align: right;\">0.00288749 </td><td style=\"text-align: right;\">0.997113</td></tr>\n",
       "<tr><td style=\"text-align: right;\">        1</td><td style=\"text-align: right;\">0.00124    </td><td style=\"text-align: right;\">0.99876 </td></tr>\n",
       "<tr><td style=\"text-align: right;\">        0</td><td style=\"text-align: right;\">0.025639   </td><td style=\"text-align: right;\">0.974361</td></tr>\n",
       "<tr><td style=\"text-align: right;\">        1</td><td style=\"text-align: right;\">0.0023271  </td><td style=\"text-align: right;\">0.997673</td></tr>\n",
       "</tbody>\n",
       "</table>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": []
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "hf_predict.tail(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "H2O session _sid_b969 closed.\n"
     ]
    }
   ],
   "source": [
    "h2o.cluster().shutdown()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
